package dao;

import java.util.ArrayList;
import java.util.List;

import model.Location;
import model.Process;
import model.ProductType;
import model.Stack;

public class Dao {

	private static Dao dao;

	private List<ProductType> productTypes;
	private List<Process> processes;
	private List<Stack> stacks;
	private List<Location> locations;

	private int stackWidth;
	private int stackHeight;

	/**
	 * Private constructor. Used for Singleton pattern.
	 * 
	 * @author Alexander Shidlovsky
	 */
	private Dao() {
		productTypes = new ArrayList<ProductType>();
		processes = new ArrayList<Process>();
		stacks = new ArrayList<Stack>();
		locations = new ArrayList<Location>();
		stackWidth = 5;
		stackHeight = 5;
	}

	/**
	 * Gets instance of Dao. Used for Singleton pattern
	 * 
	 * @author Alexander Shidlovsky
	 * @return
	 */
	public static Dao getInstance() {
		if (dao == null) {
			dao = new Dao();
		}
		return dao;
	}

	public int getStackWidth() {
		return stackWidth;
	}

	public void setStackWidth(int stackWidth) {
		this.stackWidth = stackWidth;
	}

	public int getStackHeight() {
		return stackHeight;
	}

	public void setStackHeight(int stackHeight) {
		this.stackHeight = stackHeight;
	}

	public List<ProductType> getProductTypes() {
		return new ArrayList<ProductType>(productTypes);
	}

	public List<Process> getProcesses() {
		return new ArrayList<Process>(processes);
	}

	public List<Stack> getStacks() {
		return new ArrayList<Stack>(stacks);
	}

	public List<Location> getLocations() {
		return new ArrayList<Location>(locations);
	}

	public List<Stack> getFinished() {
		List<Stack> finished = new ArrayList<Stack>();
		for (Stack x : getStacks()) {
			if (x.isFinished()) {
				finished.add(x);
			}
		}
		return finished;
	}

	public List<Stack> getWastes() {
		List<Stack> wastes = new ArrayList<Stack>();

		for (Stack x : getStacks()) {
			if (x.isWasted()) {
				wastes.add(x);
			}
		}

		return wastes;
	}

	public List<Stack> getRunningStacks() {
		List<Stack> allStacks = getStacks();
		List<Stack> runningStacks = new ArrayList<Stack>();

		for (int i = 0; i < allStacks.size(); i++) {
			if (!allStacks.get(i).isFinished() && !allStacks.get(i).isWasted())
				runningStacks.add(allStacks.get(i));
		}

		return runningStacks;
	}

	/**
	 * Stores object in List
	 * 
	 * @param obj
	 *            Object to store in database
	 * @return Stored object
	 * @author Ceslovas Lopan
	 */
	public Object store(Object obj) {
		if (obj instanceof Stack) {
			if (stacks.contains(obj))
				return obj;

			stacks.add((Stack) obj);
		} else if (obj instanceof Process) {
			if (processes.contains(obj))
				return obj;

			processes.add((Process) obj);
		} else if (obj instanceof ProductType) {
			if (productTypes.contains(obj))
				return obj;

			productTypes.add((ProductType) obj);
		} else if (obj instanceof Location) {
			if (locations.contains(obj))
				return obj;
			locations.add((Location) obj);

		}

		return obj;
	}

	/**
	 * 
	 * @author Alexey Kuprin
	 */
	public void remove(Object obj) {
		if (obj instanceof Stack) {
			if (stacks.contains(obj))
				stacks.remove(obj);
		} else if (obj instanceof ProductType) {
			if (productTypes.contains(obj))
				productTypes.remove(obj);
		} else if (obj instanceof Process) {
			if (processes.contains(obj))
				processes.remove(obj);
		}
	}

	/**
	 * Marks stack as wasted
	 * 
	 * @param stack
	 *            Wasted stack
	 * @author Alexander Shidlovsky
	 */
	public void putInWastes(Stack stack) {
		stack.setWasted(true);
		stack.setFinished(false);
		stack.removeLocation();
	}

	/**
	 * Marks stack as finished
	 * 
	 * @param stack
	 *            Finished stack
	 * @author Alexander Shidlovsky
	 */
	public void putInFinished(Stack stack) {
		stack.setFinished(true);
		stack.setWasted(false);
		stack.removeLocation();
	}
}